use abs_admin::domain::dto::{ SignInDTO,IdDTO,EmptyDTO,CatpchaDTO
    ,UserAddDTO,UserEditDTO,UserRolePageDTO
    ,ResEditDTO,PermissionAddDTO,ResPageDTO
    ,SysRoleResAddDTO,SysRoleResUpdateDTO,SysRoleResPageDTO
    ,DictAddDTO,DictEditDTO,DictPageDTO
    ,SysAuthDTO
};
use abs_admin::controller::{
    img_controller, sys_auth_controller, sys_dict_controller, sys_permission_controller,
    sys_role_controller, sys_user_controller,
};
use abs_admin::domain::table;
use abs_admin::service::CONTEXT;
use axum::Router;
use axum::routing::{get, post};
use utoipa::{Modify, OpenApi};
use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme};
use utoipa_redoc::{Redoc, Servable};
use utoipa_swagger_ui::SwaggerUi;

#[derive(OpenApi)]
#[openapi(
    paths(
        sys_user_controller::login,
        sys_user_controller::info,
        sys_user_controller::detail,
        sys_user_controller::add,
        sys_user_controller::page,
        sys_user_controller::remove,
        sys_user_controller::update,
        sys_permission_controller::layer_top,
        sys_permission_controller::all,
        sys_permission_controller::page,
        sys_permission_controller::add,
        sys_permission_controller::update,
        sys_permission_controller::remove,
        sys_role_controller::layer_top,
        sys_role_controller::page,
        sys_role_controller::add,
        sys_role_controller::update,
        sys_role_controller::remove,
        sys_dict_controller::page,
        sys_dict_controller::add,
        sys_dict_controller::update,
        sys_dict_controller::remove,
        sys_auth_controller::check,
        img_controller::captcha

    ),
    components(
        schemas(SignInDTO,IdDTO,EmptyDTO,CatpchaDTO
        ,UserAddDTO,UserEditDTO,UserRolePageDTO
        ,ResEditDTO,PermissionAddDTO,ResPageDTO
        ,SysRoleResAddDTO,SysRoleResUpdateDTO,SysRoleResPageDTO
        ,DictAddDTO,DictEditDTO,DictPageDTO
        ,SysAuthDTO
        )
    ),
    modifiers(&SecurityAddon),
    tags(
        (name = "img_controller", description = "img"),
        (name = "sys_auth_controller", description = "sys_auth"),
        (name = "sys_dict_controller", description = "sys_dict"),
        (name = "sys_permission_controller", description = "sys_permission"),
        (name = "sys_role_controller", description = "sys_role"),
        (name = "sys_user_controller", description = "sys_user"),
    ),
    security(
        (),
        ("access_token" = [])
    ),
)]
struct ApiDoc;

struct SecurityAddon;

impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "access_token",
                SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("access_token"))),
            )
        }
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    //log
    abs_admin::config::log::init_log();
    //database
    CONTEXT.init_database().await;
    table::sync_tables(&CONTEXT.rb).await;
    table::sync_tables_data(&CONTEXT.rb).await;
    //router
    let app = Router::new()
        .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
        .merge(Redoc::with_url("/redoc", ApiDoc::openapi()))
        .route("/", get(|| async { "[abs_admin] Hello !" }))
        .route("/admin/sys_login", post(sys_user_controller::login))
        .route("/admin/sys_user_info", post(sys_user_controller::info))
        .route("/admin/sys_user_detail", post(sys_user_controller::detail))
        .route("/admin/sys_user_add", post(sys_user_controller::add))
        .route("/admin/sys_user_page", post(sys_user_controller::page))
        .route("/admin/sys_user_remove", post(sys_user_controller::remove))
        .route("/admin/sys_user_update", post(sys_user_controller::update))
        .route("/admin/sys_permission_update", post(sys_permission_controller::update))
        .route("/admin/sys_permission_remove", post(sys_permission_controller::remove))
        .route("/admin/sys_permission_add", post(sys_permission_controller::add))
        .route("/admin/sys_permission_page", post(sys_permission_controller::page))
        .route("/admin/sys_permission_all", post(sys_permission_controller::all))
        .route("/admin/sys_permission_layer_top", post(sys_permission_controller::layer_top))
        .route("/admin/sys_role_add", post(sys_role_controller::add))
        .route("/admin/sys_role_update", post(sys_role_controller::update))
        .route("/admin/sys_role_delete", post(sys_role_controller::remove))
        .route("/admin/sys_role_page", post(sys_role_controller::page))
        .route("/admin/sys_role_layer_top", post(sys_role_controller::layer_top))
        .route("/admin/sys_dict_add", post(sys_dict_controller::add))
        .route("/admin/sys_dict_update", post(sys_dict_controller::update))
        .route("/admin/sys_dict_remove", post(sys_dict_controller::remove))
        .route("/admin/sys_dict_page", post(sys_dict_controller::page))
        .route("/admin/auth/check", post(sys_auth_controller::check))
        .route("/admin/captcha", get(img_controller::captcha))
        .layer(axum::middleware::from_fn(abs_admin::middleware::auth_axum::auth));
    let listener = tokio::net::TcpListener::bind(&CONTEXT.config.server_url).await.unwrap();
    axum::serve(listener, app).await
}
